package com.fx.zmlzml.algorithm.ahp;

import java.util.Arrays;

/**
 * 层次分析法（AHP）算法实现类
 *
 */
public class Ahp {

    public static void main(String[] args) {
        ahpCalc(AhpMatricesData.GAME_COMPETITION);
    }

    public static void ahpCalc(double[][] matrix) {

        System.out.println("电脑配件层次分析法(AHP)权重计算 - 游戏用途");
        System.out.println("==========================================");

        // 计算权重
        double[] weights = calculateWeights(matrix);
        // 验证判断矩阵的一致性
        double consistencyRatio = calculateConsistencyRatio(matrix);

        // 输出结果
        System.out.println("\n各配件权重结果:");
        System.out.println("配件\t\t权重\t\t占比");
        System.out.println("--------------------------------");
        double totalWeight = 0;
        for (int i = 0; i < AhpMatricesData.COMPONENTS.length; i++) {
            totalWeight += weights[i];
        }

        // 按权重排序输出
        Integer[] indices = new Integer[AhpMatricesData.COMPONENTS.length];
        for (int i = 0; i < AhpMatricesData.COMPONENTS.length; i++) {
            indices[i] = i;
        }

        // 根据权重排序
        Arrays.sort(indices, (a, b) -> Double.compare(weights[b], weights[a]));

        for (int i = 0; i < AhpMatricesData.COMPONENTS.length; i++) {
            int idx = indices[i];
            double percentage = (weights[idx] / totalWeight) * 100;
            System.out.printf("%d. %s\t\t%.4f\t\t%.2f%%%n",
                    i+1, AhpMatricesData.COMPONENTS[idx], weights[idx], percentage);
        }

        System.out.printf("\n一致性比率(CR): %.4f%n", consistencyRatio);
        if (consistencyRatio < 0.1) {
            System.out.println("一致性检验通过 (CR < 0.1)");
        } else {
            System.out.println("一致性检验未通过 (CR >= 0.1)，请重新构建判断矩阵");
        }

        // 输出判断矩阵用于验证
        System.out.println("\n判断矩阵验证:");
        printComparisonMatrix(matrix);


    }

    /**
     * 打印判断矩阵用于验证
     */
    private static void printComparisonMatrix(double[][] matrix) {
        System.out.print("\t");
        for (String component : AhpMatricesData.COMPONENTS) {
            System.out.printf("%-8s", component);
        }
        System.out.println();

        for (int i = 0; i < AhpMatricesData.COMPONENTS.length; i++) {
            System.out.print(AhpMatricesData.COMPONENTS[i] + "\t");
            for (int j = 0; j < AhpMatricesData.COMPONENTS.length; j++) {
                System.out.printf("%-8.2f", matrix[i][j]);
            }
            System.out.println();
        }
    }

    /**
     * 计算权重向量
     */
    private static double[] calculateWeights(double[][] matrix) {
        int n = AhpMatricesData.COMPONENTS.length;
        double[] weights = new double[n];

        // 1. 将判断矩阵按列归一化
        double[][] normalizedMatrix = new double[n][n];
        double[] columnSums = new double[n];

        // 计算每列的和
        for (int j = 0; j < n; j++) {
            for (int i = 0; i < n; i++) {
                columnSums[j] += matrix[i][j];
            }
        }

        // 归一化
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                normalizedMatrix[i][j] = matrix[i][j] / columnSums[j];
            }
        }

        // 2. 计算每行的平均值作为权重
        for (int i = 0; i < n; i++) {
            double rowSum = 0;
            for (int j = 0; j < n; j++) {
                rowSum += normalizedMatrix[i][j];
            }
            weights[i] = rowSum / n;
        }

        // 3. 标准化权重向量，确保总和为1
        double weightSum = 0;
        for (int i = 0; i < n; i++) {
            weightSum += weights[i];
        }

        for (int i = 0; i < n; i++) {
            weights[i] = weights[i] / weightSum;
        }

        return weights;
    }

    /**
     * 计算一致性比率
     */
    private static double calculateConsistencyRatio(double[][] matrix) {
        int n = AhpMatricesData.COMPONENTS.length;

        // 计算权重向量
        double[] weights = calculateWeights(matrix);

        // 计算Aw向量
        double[] awVector = new double[n];
        for (int i = 0; i < n; i++) {
            double sum = 0;
            for (int j = 0; j < n; j++) {
                sum += matrix[i][j] * weights[j];
            }
            awVector[i] = sum;
        }

        // 计算最大特征根λmax
        double lambdaMax = 0;
        for (int i = 0; i < n; i++) {
            // 避免除以零的情况
            if (Math.abs(weights[i]) > 1e-10) {
                lambdaMax += awVector[i] / weights[i];
            } else {
                // 如果权重接近零，使用一个较大的值避免异常
                lambdaMax += awVector[i] / 1e-10;
            }
        }
        lambdaMax /= n;

        // 计算一致性指标CI
        double ci = (lambdaMax - n) / (n - 1);

        // 查表得到随机一致性指标RI (n=8时，RI=1.41)
        // RI值来源于大量随机矩阵一致性指标的平均值，8阶矩阵的标准RI值为1.41
        /*
         * AHP随机一致性指标RI标准值表：
         * 矩阵阶数n:  1    2    3    4    5    6    7    8    9    10
         * RI值:      0    0   0.58  0.90 1.12 1.24 1.32 1.41 1.45 1.49
         */
        double ri = 1.41;

        // 计算一致性比率CR
        double cr = 0;
        if (Math.abs(ri) > 1e-10) {
            cr = ci / ri;
        }

        return cr;
    }

}
